package com.yanliang.config;

import com.yanliang.SqlSession.SqlCommandType;
import com.yanliang.pojo.Configuration;
import com.yanliang.pojo.MappedStatement;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.InputStream;
import java.util.List;
import java.util.Objects;

/**
 * 解析 xxmapper.xml 文件
 *
 * @Author : yanliang
 * @Data : 3/25/2020 5:57 PM
 */
public class XMLMapperBuilder {

    private Configuration configuration;

    public XMLMapperBuilder(Configuration configuration) {
        this.configuration = configuration;
    }

    public void parse(InputStream inputStream) {
        // 0. 通过dom4j解析配置流
        Document document = null;
        try {
            document = new SAXReader().read(inputStream);
        } catch (DocumentException e) {
            e.printStackTrace();
        }

        // 1. 解析mapper 文件，获取sql相关信息
        Element rootElement = document.getRootElement();
        String namespace = rootElement.attributeValue("namespace");

        // 2. 装载不同类型的sql命令（select/update/insert/delete）
        List<Element> selectList = rootElement.selectNodes("//select");
        setMappedStatement(namespace, selectList, SqlCommandType.SELECT);

        List<Element> insertList = rootElement.selectNodes("//insert");
        setMappedStatement(namespace, insertList, SqlCommandType.INSERT);

        List<Element> deleteList = rootElement.selectNodes("//delete");
        setMappedStatement(namespace, deleteList, SqlCommandType.DELETE);

        List<Element> updateList = rootElement.selectNodes("//update");
        setMappedStatement(namespace, updateList, SqlCommandType.UPDATE);
    }

    /**
     * 填充 mappedStatement 对象
     * @param namespace
     * @param elementList
     * @param sqlCommandType
     */
    private void setMappedStatement(String namespace, List<Element> elementList, SqlCommandType sqlCommandType) {
        if (elementList != null && !elementList.isEmpty()) {
            for (Element element : elementList) {
                // id，paramterType，resultType，sql 语句
                String id = element.attributeValue("id");
                String paramterType = element.attributeValue("parameterType");
                String resultType = element.attributeValue("resultType");
                String textTrim = element.getTextTrim();
                // 入参class
                Class<?> paramterTypeClass = getClassType(paramterType);
                // 返回值class
                Class<?> resultTypeClass = getClassType(resultType);
                // statementId
                String key = getStatementId(namespace, id);

                // 2. 封装 mappedStatement
                MappedStatement mappedStatement = new MappedStatement();
                mappedStatement.setId(id);
                mappedStatement.setParamterType(paramterTypeClass);
                mappedStatement.setResultType(resultTypeClass);
                mappedStatement.setSql(textTrim);
                mappedStatement.setSqlCommandType(sqlCommandType);
                configuration.getMappedStatementMap().put(key, mappedStatement);
            }
        }
    }

    /**
     * 通过反射获取Class对象
     * @param  paramterType
     * @return class
     * @exception/throws ClassNotFoundException
     */
    private Class<?> getClassType(String paramterType) {
        if (Objects.nonNull(paramterType)) {
            Class<?> aClass = null;
            try {
                aClass = Class.forName(paramterType);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();  // todo 异常处理优化
            }
            return aClass;
        }
        return null;
    }

    /**
     * 通过 namespace 和 select.id 拼装出statementId
     * @param  namespace, id
     * @return statementId
     * @exception/throws null
     */
    private String getStatementId(String namespace, String id) {
        return namespace +"."+id;
    }
}
